﻿using System;
using Microsoft.Practices.ObjectBuilder;

namespace Microsoft.Practices.CompositeUI
{
    /// <summary>
    /// 	Indicates that property or parameter is a dependency on a service and
    /// 	should be dependency injected when the class is put into a <see cref = "WorkItem" />.
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter)]
    public sealed class ServiceDependencyAttribute : OptionalDependencyAttribute
    {
        #region Fields & Properties

        private Type _type;

        /// <summary>
        /// 	Gets or sets the type of the service the property expects.
        /// </summary>
        public Type Type
        {
            get
            {
                return _type;
            }
            set
            {
                _type = value;
            }
        }

        #endregion

        #region Overrides of OptionalDependencyAttribute

        /// <summary>
        /// 	See <see cref = "ParameterAttribute.CreateParameter" /> for more information.
        /// </summary>
        public override IParameter CreateParameter(Type memberType)
        {
            return new ServiceDependencyParameter(_type ?? memberType, Required);
        }

        #endregion

        #region ServiceDependencyParameter Class

        private class ServiceDependencyParameter : IParameter
        {
            #region Fields & Properties

            private readonly Type _serviceType;
            private readonly bool _ensureExists;

            #endregion

            #region Constructors

            public ServiceDependencyParameter(Type serviceType, bool ensureExists)
            {
                _serviceType = serviceType;
                _ensureExists = ensureExists;
            }

            #endregion

            #region Implementation of IParameter

            public Type GetParameterType(IBuilderContext context)
            {
                return _serviceType;
            }

            public object GetValue(IBuilderContext context)
            {
                var workItem = (WorkItem) context.Locator.Get(new DependencyResolutionLocatorKey(typeof (WorkItem), null));
                return workItem.Services.Get(_serviceType, _ensureExists);
            }

            #endregion
        }

        #endregion
    }
}